package com.pai4j.zwiki.service;

import com.pai4j.common.enums.messagequeue.MessageBroadChannelEnum;
import com.pai4j.common.util.JsonUtil;
import com.pai4j.zwiki.domain.entity.ProjectAnalysisEntity;
import com.pai4j.zwiki.domain.entity.ZWikiTaskQueueEntity;
import com.pai4j.zwiki.dto.ZWikiNotificationMessage;
import com.pai4j.zwiki.enums.ZWikiNotificationType;
import com.pai4j.zwiki.service.queue.ZWikiTaskProducer;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

/**
 * ZWiki通知服务
 * 负责发送任务相关的通知和告警
 *
 * @author pai4j
 * @since 2025-10-14
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ZWikiNotificationService {

    private final ZWikiTaskProducer taskProducer;
    private final RedisTemplate<String, Object> redisTemplate;

    /**
     * 发送任务入队通知
     *
     * @param taskQueue 任务队列实体
     * @param queuePosition 队列位置
     * @param estimatedWaitTime 预计等待时间（分钟）
     */
    public void notifyTaskQueued(ZWikiTaskQueueEntity taskQueue, Integer queuePosition, Integer estimatedWaitTime) {
        try {
            ZWikiNotificationMessage notification = ZWikiNotificationMessage.builder()
                    .notificationType(ZWikiNotificationType.TASK_QUEUED.getCode())
                    .taskId(taskQueue.getTaskId())
                    .userId(taskQueue.getUserId())
                    .taskType(taskQueue.getTaskType())
                    .status("pending")
                    .queuePosition(queuePosition)
                    .estimatedWaitTime(estimatedWaitTime)
                    .title(ZWikiNotificationType.TASK_QUEUED.getTitle())
                    .message(buildQueuedMessage(taskQueue.getTaskType(), queuePosition, estimatedWaitTime))
                    .priority(getPriorityName(taskQueue.getPriority()))
                    .timestamp(System.currentTimeMillis())
                    .build();

            sendNotification(notification);
            
            log.info("发送任务入队通知: taskId={}, position={}, estimatedWait={}min", 
                    taskQueue.getTaskId(), queuePosition, estimatedWaitTime);

        } catch (Exception e) {
            log.error("发送任务入队通知失败: taskId={}", taskQueue.getTaskId(), e);
        }
    }

    /**
     * 发送任务开始处理通知
     *
     * @param taskQueue 任务队列实体
     */
    public void notifyTaskStarted(ZWikiTaskQueueEntity taskQueue) {
        try {
            ZWikiNotificationMessage notification = ZWikiNotificationMessage.builder()
                    .notificationType(ZWikiNotificationType.TASK_STARTED.getCode())
                    .taskId(taskQueue.getTaskId())
                    .userId(taskQueue.getUserId())
                    .taskType(taskQueue.getTaskType())
                    .status("processing")
                    .progress(0)
                    .title(ZWikiNotificationType.TASK_STARTED.getTitle())
                    .message("您的" + getTaskTypeName(taskQueue.getTaskType()) + "任务已开始处理")
                    .timestamp(System.currentTimeMillis())
                    .build();

            sendNotification(notification);
            
            log.info("发送任务开始处理通知: taskId={}", taskQueue.getTaskId());

        } catch (Exception e) {
            log.error("发送任务开始处理通知失败: taskId={}", taskQueue.getTaskId(), e);
        }
    }

    /**
     * 发送任务进度更新通知
     *
     * @param analysisEntity 项目分析实体
     */
    public void notifyTaskProgress(ProjectAnalysisEntity analysisEntity) {
        try {
            // 只在关键进度节点发送通知（避免频繁通知）
            if (!isKeyProgressPoint(analysisEntity.getProgress())) {
                return;
            }

            ZWikiNotificationMessage notification = ZWikiNotificationMessage.builder()
                    .notificationType(ZWikiNotificationType.TASK_PROGRESS.getCode())
                    .taskId(analysisEntity.getTaskId())
                    .userId(analysisEntity.getUserId())
                    .projectName(analysisEntity.getProjectName())
                    .status(analysisEntity.getStatus())
                    .progress(analysisEntity.getProgress())
                    .currentStep(analysisEntity.getCurrentStep())
                    .title(ZWikiNotificationType.TASK_PROGRESS.getTitle())
                    .message("任务进度: " + analysisEntity.getProgress() + "% - " + analysisEntity.getCurrentStep())
                    .timestamp(System.currentTimeMillis())
                    .build();

            sendNotification(notification);
            
            log.debug("发送任务进度通知: taskId={}, progress={}%", 
                    analysisEntity.getTaskId(), analysisEntity.getProgress());

        } catch (Exception e) {
            log.error("发送任务进度通知失败: taskId={}", analysisEntity.getTaskId(), e);
        }
    }

    /**
     * 发送任务完成通知
     *
     * @param analysisEntity 项目分析实体
     */
    public void notifyTaskCompleted(ProjectAnalysisEntity analysisEntity) {
        try {
            ZWikiNotificationMessage notification = ZWikiNotificationMessage.builder()
                    .notificationType(ZWikiNotificationType.TASK_COMPLETED.getCode())
                    .taskId(analysisEntity.getTaskId())
                    .userId(analysisEntity.getUserId())
                    .projectName(analysisEntity.getProjectName())
                    .status("completed")
                    .progress(100)
                    .title(ZWikiNotificationType.TASK_COMPLETED.getTitle())
                    .message(buildCompletedMessage(analysisEntity))
                    .timestamp(System.currentTimeMillis())
                    .build();

            sendNotification(notification);
            
            log.info("发送任务完成通知: taskId={}, projectName={}", 
                    analysisEntity.getTaskId(), analysisEntity.getProjectName());

        } catch (Exception e) {
            log.error("发送任务完成通知失败: taskId={}", analysisEntity.getTaskId(), e);
        }
    }

    /**
     * 发送任务失败通知
     *
     * @param taskQueue 任务队列实体
     * @param errorMessage 错误信息
     */
    public void notifyTaskFailed(ZWikiTaskQueueEntity taskQueue, String errorMessage) {
        try {
            ZWikiNotificationMessage notification = ZWikiNotificationMessage.builder()
                    .notificationType(ZWikiNotificationType.TASK_FAILED.getCode())
                    .taskId(taskQueue.getTaskId())
                    .userId(taskQueue.getUserId())
                    .taskType(taskQueue.getTaskType())
                    .status("failed")
                    .errorMessage(errorMessage)
                    .title(ZWikiNotificationType.TASK_FAILED.getTitle())
                    .message("您的任务处理失败: " + errorMessage)
                    .timestamp(System.currentTimeMillis())
                    .build();

            sendNotification(notification);
            
            log.warn("发送任务失败通知: taskId={}, error={}", taskQueue.getTaskId(), errorMessage);

        } catch (Exception e) {
            log.error("发送任务失败通知异常: taskId={}", taskQueue.getTaskId(), e);
        }
    }

    /**
     * 发送队列位置更新通知
     *
     * @param taskQueue 任务队列实体
     * @param newPosition 新位置
     */
    public void notifyQueuePositionUpdate(ZWikiTaskQueueEntity taskQueue, Integer newPosition) {
        try {
            // 只在位置有显著变化时通知
            if (newPosition != null && newPosition % 5 == 0) {
                ZWikiNotificationMessage notification = ZWikiNotificationMessage.builder()
                        .notificationType(ZWikiNotificationType.QUEUE_POSITION_UPDATE.getCode())
                        .taskId(taskQueue.getTaskId())
                        .userId(taskQueue.getUserId())
                        .queuePosition(newPosition)
                        .title(ZWikiNotificationType.QUEUE_POSITION_UPDATE.getTitle())
                        .message("您在队列中的位置: 第" + newPosition + "位")
                        .timestamp(System.currentTimeMillis())
                        .build();

                sendNotification(notification);
            }

        } catch (Exception e) {
            log.error("发送队列位置更新通知失败: taskId={}", taskQueue.getTaskId(), e);
        }
    }

    /**
     * 发送通知消息到队列（同时支持RocketMQ和Redis）
     */
    private void sendNotification(ZWikiNotificationMessage notification) {
        try {
            String message = JsonUtil.toJsonString(notification);
            
            // 1. 发送到RocketMQ（用于持久化和异步处理）
            taskProducer.sendNotification(message);
            
            // 2. 发送到Redis发布订阅（用于实时推送）
            publishToRedis(notification);
            
        } catch (Exception e) {
            log.error("发送通知失败", e);
        }
    }
    
    /**
     * 发布通知到Redis（发布订阅模式）
     */
    private void publishToRedis(ZWikiNotificationMessage notification) {
        try {
            String message = JsonUtil.toJsonString(notification);
            
            // 根据通知类型选择不同的频道
            String channel = getRedisChannelByNotificationType(notification.getNotificationType());
            
            // 发布到Redis频道
            redisTemplate.convertAndSend(channel, message);
            
            log.debug("通知已发布到Redis频道: channel={}, type={}, taskId={}", 
                    channel, notification.getNotificationType(), notification.getTaskId());
                    
        } catch (Exception e) {
            log.error("发布到Redis失败", e);
            // Redis发布失败不影响主流程
        }
    }
    
    /**
     * 根据通知类型获取Redis频道
     */
    private String getRedisChannelByNotificationType(String notificationType) {
        if (notificationType == null) {
            return MessageBroadChannelEnum.QUEUE_ZWIKI_TASK_NOTIFICATION.getChannel();
        }
        
        try {
            ZWikiNotificationType type = ZWikiNotificationType.valueOf(notificationType);
            
            return switch (type) {
                case TASK_PROGRESS -> 
                    MessageBroadChannelEnum.QUEUE_ZWIKI_TASK_PROGRESS.getChannel();
                case QUEUE_POSITION_UPDATE -> 
                    MessageBroadChannelEnum.QUEUE_ZWIKI_QUEUE_UPDATE.getChannel();
                default -> 
                    MessageBroadChannelEnum.QUEUE_ZWIKI_TASK_NOTIFICATION.getChannel();
            };
            
        } catch (Exception e) {
            return MessageBroadChannelEnum.QUEUE_ZWIKI_TASK_NOTIFICATION.getChannel();
        }
    }

    /**
     * 构建入队消息
     */
    private String buildQueuedMessage(String taskType, Integer position, Integer estimatedWaitTime) {
        String typeName = getTaskTypeName(taskType);
        StringBuilder msg = new StringBuilder();
        msg.append("您的").append(typeName).append("任务已成功加入处理队列。\n");
        msg.append("当前队列位置: 第").append(position).append("位\n");
        
        if (estimatedWaitTime != null && estimatedWaitTime > 0) {
            if (estimatedWaitTime < 60) {
                msg.append("预计等待时间: 约").append(estimatedWaitTime).append("分钟");
            } else {
                int hours = estimatedWaitTime / 60;
                int minutes = estimatedWaitTime % 60;
                msg.append("预计等待时间: 约").append(hours).append("小时");
                if (minutes > 0) {
                    msg.append(minutes).append("分钟");
                }
            }
        }
        
        return msg.toString();
    }

    /**
     * 构建完成消息
     */
    private String buildCompletedMessage(ProjectAnalysisEntity entity) {
        StringBuilder msg = new StringBuilder();
        msg.append("🎉 项目「").append(entity.getProjectName()).append("」分析完成！\n\n");
        msg.append("📊 分析结果:\n");
        
        if (entity.getTotalFiles() != null) {
            msg.append("- 总文件数: ").append(entity.getTotalFiles()).append("\n");
        }
        if (entity.getJavaFiles() != null) {
            msg.append("- Java文件: ").append(entity.getJavaFiles()).append("\n");
        }
        if (entity.getTotalLines() != null) {
            msg.append("- 代码总行数: ").append(entity.getTotalLines()).append("\n");
        }
        
        msg.append("\n您现在可以查看详细报告和下载论文了！");
        
        return msg.toString();
    }

    /**
     * 判断是否为关键进度点（避免频繁通知）
     */
    private boolean isKeyProgressPoint(Integer progress) {
        if (progress == null) {
            return false;
        }
        // 在25%, 50%, 75%时发送通知
        return progress == 25 || progress == 50 || progress == 75;
    }

    /**
     * 获取任务类型名称
     */
    private String getTaskTypeName(String taskType) {
        if (taskType == null) {
            return "未知";
        }
        switch (taskType) {
            case "project_analysis":
                return "项目分析";
            case "thesis_generation":
                return "论文生成";
            case "thesis_optimization":
                return "论文优化";
            default:
                return taskType;
        }
    }

    /**
     * 获取优先级名称
     */
    private String getPriorityName(Integer priority) {
        if (priority == null) {
            return "普通";
        }
        if (priority >= 10) {
            return "紧急";
        } else if (priority >= 5) {
            return "高";
        } else if (priority >= 3) {
            return "普通";
        } else {
            return "低";
        }
    }
}

